package com.bluexmicro.bluetooth.peripheral.handler

import android.annotation.SuppressLint
import android.bluetooth.BluetoothGatt
import android.bluetooth.BluetoothGattService
import com.bluexmicro.bluetooth.LogUtils
import com.bluexmicro.bluetooth.model.GattStatus
import kotlinx.coroutines.CancellableContinuation
import kotlinx.coroutines.suspendCancellableCoroutine
import kotlin.coroutines.resume

typealias OnDiscoveredCallback = (gatt: BluetoothGatt, status: Int) -> Unit

class DiscoverServicesHandler {

    private var callback: OnDiscoveredCallback? = null
    private var cancellableContinuation: CancellableContinuation<Result<List<BluetoothGattService>>>? =
        null

    fun onServicesDiscovered(gatt: BluetoothGatt, status: Int) {
        callback?.invoke(gatt, status)
    }

    private fun setCallback(cb: OnDiscoveredCallback) {
        this.callback = cb
    }

    fun isActive(): Boolean {
        return cancellableContinuation?.isActive == true
    }

    @SuppressLint("MissingPermission")
    suspend fun execute(gatt: BluetoothGatt, failedToDisconnect: Boolean = true) =
        suspendCancellableCoroutine<Result<List<BluetoothGattService>>> {
            cancellableContinuation = it
            setCallback { g, status ->
                this.callback = null
                if (status == BluetoothGatt.GATT_SUCCESS) {
                    if (it.isActive) {
                        it.resume(Result.success(g.services))
                    }

                } else {
                    if (failedToDisconnect) {
                        g.disconnect()
                        g.close()
                    }
                    if (it.isActive) {
                        val reason = GattStatus.fromValue(status).name
                        it.resume(Result.failure(IllegalStateException("discoverServices failed(code: $status, reason: $reason)")))
                    }
                }
            }
            val res = gatt.discoverServices()
            LogUtils.sendLog(
                mapOf(
                    "mac" to gatt.device.address,
                    "call method" to "discoverServices",
                    "detail" to if (res) "done" else "failed"
                )
            )
            if (!res) {
                this.callback = null
                if (it.isActive) {
                    it.resume(Result.failure(IllegalStateException("discoverServices failed")))
                }
            }

            it.invokeOnCancellation {
                this.callback = null
            }
        }
}